//+------------------------------------------------------------------+
//|                                           BollingerRSI_EA.mq5    |
//|                        基于布林带+RSI的专业交易EA                  |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Your Name"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "基于布林带和RSI的智能交易EA，支持多种移动平均类型和灵活的出入场策略"

#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>

//--- 输入参数
input group "=== 布林带参数 ==="
input int                InpBB_Period = 20;                    // 布林带周期
input double             InpBB_Deviation = 2.0;                // 布林带标准差倍数
input ENUM_MA_METHOD     InpBB_Method = MODE_SMA;              // 布林带移动平均类型 (SMA, EMA, SMMA, LWMA)
input ENUM_APPLIED_PRICE InpBB_AppliedPrice = PRICE_CLOSE;     // 布林带应用价格
input int                InpBB_Shift = 0;                      // 布林带偏移

input group "=== RSI参数 ==="
input bool               InpUseRSI = true;                     // 是否使用RSI过滤
input int                InpRSI_Period = 14;                   // RSI周期
input ENUM_APPLIED_PRICE InpRSI_AppliedPrice = PRICE_CLOSE;    // RSI应用价格
input double             InpRSI_Overbought = 70.0;             // RSI超买线
input double             InpRSI_Oversold = 30.0;               // RSI超卖线
input bool               InpRSI_UseSignalCross = true;         // 使用RSI信号线交叉

input group "=== 入场策略 ==="
input bool               InpUseBBBounce = true;                // 使用布林带反弹策略
input bool               InpUseBBBreakout = false;             // 使用布林带突破策略
input bool               InpRequireVolumeConfirm = false;      // 需要成交量确认
input int                InpMinCandlesFromBB = 1;              // 距离布林带的最小K线数

input group "=== 交易参数 ==="
input double             InpLotSize = 0.1;                     // 固定手数
input bool               InpUseAutoLot = false;                // 使用自动手数
input double             InpRiskPercent = 2.0;                 // 风险百分比(自动手数时)
input int                InpMagicNumber = 123456;              // 魔术号
input int                InpSlippage = 10;                     // 滑点
input bool               InpTradeOnNewBar = true;              // 仅在新K线交易

input group "=== 风险管理 ==="
input bool               InpUseFixedSLTP = true;               // 使用固定止损止盈
input double             InpFixedSL = 100.0;                   // 固定止损点数
input double             InpFixedTP = 200.0;                   // 固定止盈点数
input bool               InpUseATRSLTP = false;                // 使用ATR动态止损止盈
input int                InpATR_Period = 14;                   // ATR周期
input double             InpATR_SL_Multiplier = 2.0;           // ATR止损倍数
input double             InpATR_TP_Multiplier = 3.0;           // ATR止盈倍数

input group "=== 出场策略 ==="
input bool               InpUseBBExit = true;                  // 使用布林带出场
input bool               InpUseRSIExit = true;                 // 使用RSI出场
input bool               InpUseTrailingStop = false;           // 使用追踪止损
input double             InpTrailingStart = 50.0;              // 追踪止损启动点数
input double             InpTrailingStep = 20.0;               // 追踪止损步长

input group "=== 时间过滤 ==="
input bool               InpUseTimeFilter = false;             // 使用时间过滤
input int                InpStartHour = 8;                     // 开始小时
input int                InpEndHour = 20;                      // 结束小时

//--- 全局变量
CTrade         m_trade;
CSymbolInfo    m_symbol;
CPositionInfo  m_position;

int            m_bb_handle;           // 布林带句柄
int            m_rsi_handle;          // RSI句柄
int            m_atr_handle;          // ATR句柄
datetime       m_last_bar_time;      // 上一根K线时间

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // 设置交易参数
    m_trade.SetExpertMagicNumber(InpMagicNumber);
    m_trade.SetDeviationInPoints(InpSlippage);
    m_trade.SetTypeFilling(ORDER_FILLING_FOK);
    m_trade.SetTypeExpiration(ORDER_TIME_GTC);
    
    // 初始化品种信息
    if(!m_symbol.Name(_Symbol))
    {
        Print("错误：无法初始化品种信息");
        return INIT_FAILED;
    }
    
    // 创建布林带指标 - 注意：MQL5的iBands只支持SMA，如果需要其他MA类型需要自定义
    m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, InpBB_Period, InpBB_Shift, InpBB_Deviation, InpBB_AppliedPrice);
    if(m_bb_handle == INVALID_HANDLE)
    {
        Print("错误：无法创建布林带指标，错误代码：", GetLastError());
        return INIT_FAILED;
    }
    
    // 创建RSI指标（如果启用）
    if(InpUseRSI)
    {
        m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, InpRSI_Period, InpRSI_AppliedPrice);
        if(m_rsi_handle == INVALID_HANDLE)
        {
            Print("错误：无法创建RSI指标，错误代码：", GetLastError());
            return INIT_FAILED;
        }
    }
    
    // 创建ATR指标（如果使用ATR止损止盈）
    if(InpUseATRSLTP)
    {
        m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, InpATR_Period);
        if(m_atr_handle == INVALID_HANDLE)
        {
            Print("错误：无法创建ATR指标，错误代码：", GetLastError());
            return INIT_FAILED;
        }
    }
    
    // 初始化时间
    m_last_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
    
    Print("布林带+RSI EA 初始化成功");
    Print("布林带参数：周期=", InpBB_Period, " 标准差=", InpBB_Deviation);
    Print("RSI参数：", InpUseRSI ? "启用" : "禁用", " 周期=", InpRSI_Period);
    Print("交易手数：", InpUseAutoLot ? "自动(" + DoubleToString(InpRiskPercent, 1) + "%)" : DoubleToString(InpLotSize, 2));
    
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // 释放指标句柄
    if(m_bb_handle != INVALID_HANDLE)
        IndicatorRelease(m_bb_handle);
    if(m_rsi_handle != INVALID_HANDLE)
        IndicatorRelease(m_rsi_handle);
    if(m_atr_handle != INVALID_HANDLE)
        IndicatorRelease(m_atr_handle);
    
    Print("EA已卸载，原因：", reason);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 检查新K线
    if(InpTradeOnNewBar)
    {
        datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
        if(current_bar_time == m_last_bar_time)
            return;
        m_last_bar_time = current_bar_time;
    }
    
    // 时间过滤
    if(InpUseTimeFilter && !IsTimeToTrade())
        return;
    
    // 检查是否有持仓
    bool has_position = false;
    if(m_position.Select(_Symbol))
    {
        if(m_position.Magic() == InpMagicNumber)
            has_position = true;
    }
    
    // 如果有持仓，检查出场条件和追踪止损
    if(has_position)
    {
        CheckExitConditions();
        if(InpUseTrailingStop)
            CheckTrailingStop();
        return;
    }
    
    // 检查入场条件
    CheckEntryConditions();
}

//+------------------------------------------------------------------+
//| 检查是否在交易时间                                               |
//+------------------------------------------------------------------+
bool IsTimeToTrade()
{
    MqlDateTime dt;
    TimeToStruct(TimeCurrent(), dt);
    
    return (dt.hour >= InpStartHour && dt.hour < InpEndHour);
}

//+------------------------------------------------------------------+
//| 检查入场条件                                                     |
//+------------------------------------------------------------------+
void CheckEntryConditions()
{
    // 获取布林带数据
    double bb_upper[], bb_middle[], bb_lower[];
    ArraySetAsSeries(bb_upper, true);
    ArraySetAsSeries(bb_middle, true);
    ArraySetAsSeries(bb_lower, true);
    
    if(CopyBuffer(m_bb_handle, 1, 0, 5, bb_upper) < 5 ||
       CopyBuffer(m_bb_handle, 0, 0, 5, bb_middle) < 5 ||
       CopyBuffer(m_bb_handle, 2, 0, 5, bb_lower) < 5)
    {
        Print("错误：无法获取布林带数据");
        return;
    }
    
    // 获取RSI数据（如果启用）
    double rsi_current = 50.0, rsi_prev = 50.0;
    if(InpUseRSI)
    {
        double rsi[];
        ArraySetAsSeries(rsi, true);
        
        if(CopyBuffer(m_rsi_handle, 0, 0, 3, rsi) < 3)
        {
            Print("错误：无法获取RSI数据");
            return;
        }
        
        rsi_current = rsi[1];  // 使用上一根完成的K线数据
        rsi_prev = rsi[2];
    }
    
    // 获取价格数据（使用完成的K线）
    double close_1 = iClose(_Symbol, PERIOD_CURRENT, 1);
    double close_2 = iClose(_Symbol, PERIOD_CURRENT, 2);
    double close_3 = iClose(_Symbol, PERIOD_CURRENT, 3);
    double high_1 = iHigh(_Symbol, PERIOD_CURRENT, 1);
    double low_1 = iLow(_Symbol, PERIOD_CURRENT, 1);
    
    bool buy_signal = false;
    bool sell_signal = false;
    
    // 布林带反弹策略
    if(InpUseBBBounce)
    {
        // 买入信号：价格触及下轨后反弹
        if(low_1 <= bb_lower[1] && close_1 > bb_lower[1] && close_1 > close_2)
        {
            buy_signal = true;
            Print("检测到布林带下轨反弹买入信号");
        }
        
        // 卖出信号：价格触及上轨后回落
        if(high_1 >= bb_upper[1] && close_1 < bb_upper[1] && close_1 < close_2)
        {
            sell_signal = true;
            Print("检测到布林带上轨回落卖出信号");
        }
    }
    
    // 布林带突破策略
    if(InpUseBBBreakout)
    {
        // 买入信号：突破上轨
        if(close_2 <= bb_upper[2] && close_1 > bb_upper[1])
        {
            buy_signal = true;
            Print("检测到布林带上轨突破买入信号");
        }
        
        // 卖出信号：跌破下轨
        if(close_2 >= bb_lower[2] && close_1 < bb_lower[1])
        {
            sell_signal = true;
            Print("检测到布林带下轨突破卖出信号");
        }
    }
    
    // RSI过滤
    if(InpUseRSI && (buy_signal || sell_signal))
    {
        if(buy_signal)
        {
            if(InpRSI_UseSignalCross)
            {
                // RSI从超卖区域向上穿越
                buy_signal = (rsi_prev <= InpRSI_Oversold && rsi_current > InpRSI_Oversold) ||
                            (rsi_current > InpRSI_Oversold && rsi_current < InpRSI_Overbought);
            }
            else
            {
                buy_signal = rsi_current < InpRSI_Overbought;
            }
        }
        
        if(sell_signal)
        {
            if(InpRSI_UseSignalCross)
            {
                // RSI从超买区域向下穿越
                sell_signal = (rsi_prev >= InpRSI_Overbought && rsi_current < InpRSI_Overbought) ||
                             (rsi_current < InpRSI_Overbought && rsi_current > InpRSI_Oversold);
            }
            else
            {
                sell_signal = rsi_current > InpRSI_Oversold;
            }
        }
    }
    
    // 执行交易
    if(buy_signal)
    {
        OpenBuyPosition();
    }
    else if(sell_signal)
    {
        OpenSellPosition();
    }
}

//+------------------------------------------------------------------+
//| 计算手数                                                         |
//+------------------------------------------------------------------+
double CalculateLotSize(double sl_distance)
{
    if(!InpUseAutoLot)
        return InpLotSize;
    
    double account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
    double risk_amount = account_balance * InpRiskPercent / 100.0;
    double tick_value = m_symbol.TickValue();
    double tick_size = m_symbol.TickSize();
    
    double lot_size = risk_amount / (sl_distance / tick_size * tick_value);
    
    // 标准化手数
    double min_lot = m_symbol.LotsMin();
    double max_lot = m_symbol.LotsMax();
    double lot_step = m_symbol.LotsStep();
    
    lot_size = MathMax(min_lot, MathMin(max_lot, MathFloor(lot_size / lot_step) * lot_step));
    
    return lot_size;
}

//+------------------------------------------------------------------+
//| 开多头仓位                                                       |
//+------------------------------------------------------------------+
void OpenBuyPosition()
{
    double ask = m_symbol.Ask();
    double sl = 0, tp = 0;
    double atr_value = 0;
    
    // 计算止损止盈
    if(InpUseATRSLTP)
    {
        double atr[];
        ArraySetAsSeries(atr, true);
        if(CopyBuffer(m_atr_handle, 0, 0, 1, atr) >= 1)
        {
            atr_value = atr[0];
            sl = ask - InpATR_SL_Multiplier * atr_value;
            tp = ask + InpATR_TP_Multiplier * atr_value;
        }
    }
    else if(InpUseFixedSLTP)
    {
        sl = ask - InpFixedSL * m_symbol.Point();
        tp = ask + InpFixedTP * m_symbol.Point();
    }
    
    // 计算手数
    double lot_size = CalculateLotSize(MathAbs(ask - sl));
    
    // 发送订单
    if(m_trade.Buy(lot_size, _Symbol, ask, sl, tp, "BB+RSI Buy"))
    {
        Print("买入订单成功：手数=", lot_size, " 价格=", ask, " 止损=", sl, " 止盈=", tp);
    }
    else
    {
        Print("买入订单失败：", m_trade.ResultRetcode(), " - ", m_trade.ResultComment());
    }
}

//+------------------------------------------------------------------+
//| 开空头仓位                                                       |
//+------------------------------------------------------------------+
void OpenSellPosition()
{
    double bid = m_symbol.Bid();
    double sl = 0, tp = 0;
    double atr_value = 0;
    
    // 计算止损止盈
    if(InpUseATRSLTP)
    {
        double atr[];
        ArraySetAsSeries(atr, true);
        if(CopyBuffer(m_atr_handle, 0, 0, 1, atr) >= 1)
        {
            atr_value = atr[0];
            sl = bid + InpATR_SL_Multiplier * atr_value;
            tp = bid - InpATR_TP_Multiplier * atr_value;
        }
    }
    else if(InpUseFixedSLTP)
    {
        sl = bid + InpFixedSL * m_symbol.Point();
        tp = bid - InpFixedTP * m_symbol.Point();
    }
    
    // 计算手数
    double lot_size = CalculateLotSize(MathAbs(sl - bid));
    
    // 发送订单
    if(m_trade.Sell(lot_size, _Symbol, bid, sl, tp, "BB+RSI Sell"))
    {
        Print("卖出订单成功：手数=", lot_size, " 价格=", bid, " 止损=", sl, " 止盈=", tp);
    }
    else
    {
        Print("卖出订单失败：", m_trade.ResultRetcode(), " - ", m_trade.ResultComment());
    }
}

//+------------------------------------------------------------------+
//| 检查出场条件                                                     |
//+------------------------------------------------------------------+
void CheckExitConditions()
{
    if(!m_position.Select(_Symbol) || m_position.Magic() != InpMagicNumber)
        return;
    
    bool should_close = false;
    string close_reason = "";
    
    // 获取当前价格
    double current_price = (m_position.PositionType() == POSITION_TYPE_BUY) ? 
                           m_symbol.Bid() : m_symbol.Ask();
    
    // 布林带出场
    if(InpUseBBExit)
    {
        double bb_middle[], bb_upper[], bb_lower[];
        ArraySetAsSeries(bb_middle, true);
        ArraySetAsSeries(bb_upper, true);
        ArraySetAsSeries(bb_lower, true);
        
        if(CopyBuffer(m_bb_handle, 0, 0, 2, bb_middle) >= 2 &&
           CopyBuffer(m_bb_handle, 1, 0, 2, bb_upper) >= 2 &&
           CopyBuffer(m_bb_handle, 2, 0, 2, bb_lower) >= 2)
        {
            // 多头仓位：价格回到中轨或触及上轨
            if(m_position.PositionType() == POSITION_TYPE_BUY)
            {
                if(current_price <= bb_middle[1] || current_price >= bb_upper[1])
                {
                    should_close = true;
                    close_reason = "布林带出场-多头";
                }
            }
            // 空头仓位：价格回到中轨或触及下轨
            else if(m_position.PositionType() == POSITION_TYPE_SELL)
            {
                if(current_price >= bb_middle[1] || current_price <= bb_lower[1])
                {
                    should_close = true;
                    close_reason = "布林带出场-空头";
                }
            }
        }
    }
    
    // RSI出场
    if(InpUseRSIExit && InpUseRSI && !should_close)
    {
        double rsi[];
        ArraySetAsSeries(rsi, true);
        
        if(CopyBuffer(m_rsi_handle, 0, 0, 2, rsi) >= 2)
        {
            // 多头仓位在RSI超买时平仓
            if(m_position.PositionType() == POSITION_TYPE_BUY && rsi[1] >= InpRSI_Overbought)
            {
                should_close = true;
                close_reason = "RSI超买出场";
            }
            // 空头仓位在RSI超卖时平仓
            else if(m_position.PositionType() == POSITION_TYPE_SELL && rsi[1] <= InpRSI_Oversold)
            {
                should_close = true;
                close_reason = "RSI超卖出场";
            }
        }
    }
    
    // 执行平仓
    if(should_close)
    {
        if(m_trade.PositionClose(_Symbol))
        {
            Print("仓位已平仓，原因：", close_reason);
        }
        else
        {
            Print("平仓失败：", m_trade.ResultRetcode(), " - ", m_trade.ResultComment());
        }
    }
}

//+------------------------------------------------------------------+
//| 检查追踪止损                                                     |
//+------------------------------------------------------------------+
void CheckTrailingStop()
{
    if(!m_position.Select(_Symbol) || m_position.Magic() != InpMagicNumber)
        return;
    
    double sl = m_position.StopLoss();
    double open_price = m_position.PriceOpen();
    
    if(m_position.PositionType() == POSITION_TYPE_BUY)
    {
        double bid = m_symbol.Bid();
        double new_sl = bid - InpTrailingStep * m_symbol.Point();
        
        // 检查是否达到启动条件且新止损更有利
        if(bid - open_price >= InpTrailingStart * m_symbol.Point() && 
           (sl == 0 || new_sl > sl + m_symbol.Point()))
        {
            if(m_trade.PositionModify(_Symbol, new_sl, m_position.TakeProfit()))
            {
                Print("追踪止损已更新：", new_sl);
            }
        }
    }
    else if(m_position.PositionType() == POSITION_TYPE_SELL)
    {
        double ask = m_symbol.Ask();
        double new_sl = ask + InpTrailingStep * m_symbol.Point();
        
        // 检查是否达到启动条件且新止损更有利
        if(open_price - ask >= InpTrailingStart * m_symbol.Point() && 
           (sl == 0 || new_sl < sl - m_symbol.Point()))
        {
            if(m_trade.PositionModify(_Symbol, new_sl, m_position.TakeProfit()))
            {
                Print("追踪止损已更新：", new_sl);
            }
        }
    }
} 